#include "engine.h"
#include "json.h"


json_object_t& json_value_t::create_object()
{
	ASSERT(val_type==type_undefined);
	this->obj=new json_object_t;
	val_type=type_obj;
	return *obj;
}

json_array_t& json_value_t::create_array()
{
	ASSERT(val_type==type_undefined);
	this->arr=new json_array_t;
	val_type=type_arr;
	return *arr;

}

json_value_t::operator float2()// const
{
	return float2((float)get_array().value_list[0].get_num(), (float)get_array().value_list[1].get_num());
}

json_value_t::operator float3()// const
{
	return float3((float)get_array().value_list[0].get_num(), (float)get_array().value_list[1].get_num(), (float)get_array().value_list[2].get_num());

}

void json_value_t::free()
{
	switch (val_type)
	{
	case type_str:
		delete str;
		break;
	case type_obj:
		delete obj;
		break;
	case type_arr:
		delete arr;
		break;
	}

	val_type=type_undefined;
}

void json_value_t::copy(const json_value_t& other)
{
	ASSERT(val_type==type_undefined);
	val_type=other.val_type;
	switch (val_type)
	{
	case type_num:
		num=other.num;
		break;
	case type_int:
		int_num=other.int_num;
		break;
	case type_bool:
		b=other.b;
		break;
	case type_str:
		str=new string(*other.str);
		break;
	case type_obj:
		obj=new json_object_t;
		obj->copy(*other.obj);
		break;
	case type_arr:
		arr=new json_array_t;
		arr->copy(*other.arr);
		break;
	default:
		ASSERTTXT(0,"MIEEEERT?");
		break;
	}

}


enum token_type
{
	tok_str,
	tok_hash,
	tok_number,
	tok_int,
	tok_comma,
	tok_colon,
	tok_left_bracket,
	tok_right_bracket,
	tok_left_brace,
	tok_right_brace,
	tok_bool,
	tok_nil,
	tok_eof
};

struct json_parser_t
{
	json_parser_t();
	void process_text(const char* text,json_object_t*);
	void process_binary(const char* bin,json_object_t*);

	json_object_t* proc_json();
	void proc_object(json_object_t&);
	void proc_array(json_array_t&);
	json_pair_t proc_pair();
	json_value_t proc_value();

	void get_next_token();

	void get_number();
	void get_int();
	void get_string();
	void get_hash();
	void get_left_bracket();
	void get_right_bracket();
	void get_left_brace();
	void get_right_brace();
	void get_comma();
	void get_colon();
	void get_true_val();
	void get_false_val();
	void get_nil_val();
	void get_eof();

	bool accept(token_type s);
	bool expect(token_type s);

	const char* text;
	//	json_object_t* map;
	int text_size;
	int act_index;
	int utf8_diff;

	token_type act_token;
	bool bool_val;
	char str_val[JSON_STRING_BUFFER_SIZE];
	stringhash hash_val;
	float number_val;
	int int_val;

	bool success;
	string error_string;
};

json_parser_t::json_parser_t()
{
	text=NULL;
	//	map=NULL;
	success=true;
}

bool json_parser_t::accept(token_type s)
{
	if (act_token==s)
	{
		get_next_token();
	}
	else
	{
		error_string=string(_str("unexpected token %d [%d: %+d] next 10 chars: ",act_index+utf8_diff,act_index,utf8_diff))+string(text+act_index,10);
		success=false;
	}
	return success;
}

bool json_parser_t::expect(token_type s)
{
	return accept(s);
}

void json_parser_t::process_text(const char* text,json_object_t* m)
{
	if (text[0]==char(0xEF) && text[1]==char(0xBB) && text[2]==char(0xBF)) // utf8 files starts with 0xEF 0xBB 0BF, read over it
		text+=3;

	this->text=text;
	text_size=strlen(text);
	act_index=0;
	utf8_diff=0;
	success=true;
	//	map=NULL;

	get_next_token();

	if (success && accept(tok_left_brace))
	{
		//		map=new json_object_t;
		proc_object(*m);

		if (success)
			expect(tok_right_brace);
	}
}

void load_bin_value(json_parser_t* p, json_value_t& v);
void load_bin_object(json_parser_t* p, json_object_t& o);
void json_parser_t::process_binary(const char *bin,json_object_t* m)
{
	this->text=bin;
	act_index=0;
	utf8_diff=0;
//	map=new json_object_t;
	load_bin_object(this,*m);
}

void load_bin_value(json_parser_t* p, json_value_t& v);
void load_bin_object(json_parser_t* p, json_object_t& o)
{
	unsigned size;

	memcpy(&size,p->text+p->act_index,4);
	p->act_index+=4;

	o.pair_list.resize(size);

	for (unsigned n=0; n<size; ++n)
	{
		memcpy(&o.pair_list[n].key.value,p->text+p->act_index,4);
		p->act_index+=4;
		load_bin_value(p,o.pair_list[n].val);
	}
}

void load_bin_array(json_parser_t* p, json_array_t& a)
{
	unsigned size;

	memcpy(&size,p->text+p->act_index,4);
	p->act_index+=4;

	a.value_list.resize(size);

	for (unsigned n=0; n<size; ++n)
	{
		load_bin_value(p,a.value_list[n]);
	}
}
void load_bin_value(json_parser_t* p, json_value_t& v)
{
	uint8 type;
	type=p->text[p->act_index];
	++p->act_index;

	if (type==100)
	{
		v.set_num(0);
		return;
	}
	if (type==101)
	{
		v.set_int(0);
		return;
	}

	switch (type)
	{
	case type_num:
		{
			float f;
			memcpy(&f,p->text+p->act_index,4);
			p->act_index+=4;
			v.set_num(f);
			break;
		}
	case type_str:
		{
			uint16 size;
			memcpy(&size,p->text+p->act_index,2);
			p->act_index+=2;
			v.set_str(p->text+p->act_index);
			p->act_index+=size;
			break;
		}
	case type_hash:
		{
			stringhash f;
			memcpy(&f.value,p->text+p->act_index,4);
			p->act_index+=4;
			v.set_hash(stringhash(f));
			break;
		}
	case type_bool:
		{
			uint8 b;
			b=p->text[p->act_index];
			++p->act_index;
			v.set_bool(b!=0);
			break;
		}
	case type_nil:
		ASSERT(0);
		break;
	case type_int:
		{
			int f;
			memcpy(&f,p->text+p->act_index,4);
			p->act_index+=4;
			v.set_int(f);
			break;
		}
	case type_obj:
		load_bin_object(p,v.create_object());
		break;
	case type_arr:
		load_bin_array(p,v.create_array());
		break;
	default:
		ASSERT(0);
		break;
	}
}


void json_parser_t::proc_object(json_object_t& obj)
{
	obj.pair_list.reserve(2000);
	while (act_token!=tok_right_brace)
	{
		json_pair_t pair=proc_pair();
		if (!success)
			break;
		obj.pair_list.push_back(pair);

		while (act_token==tok_comma)
		{
			if (!accept(tok_comma))
				break;
		}
	}
	vector<json_pair_t> tmp;
	tmp.resize(obj.pair_list.size());
	for (unsigned n=0; n<tmp.size(); ++n)
	{
		tmp[n]=obj.pair_list[n];
	}
	obj.pair_list.swap(tmp);

}

json_pair_t json_parser_t::proc_pair()
{
	json_pair_t pair;

	if (act_token==tok_str)
		pair.key.make(&str_val[0]);

	if (expect(tok_str))
	if (expect(tok_colon))
	pair.val=proc_value();

	return pair;
}

json_value_t json_parser_t::proc_value()
{
	json_value_t val;
	switch (act_token)
	{
	case tok_str:
		val.set_str(&str_val[0]);
		accept(tok_str);
		break;
	case tok_hash:
		val.set_hash(hash_val);
		accept(tok_hash);
		break;
	case tok_number:
		val.set_num(number_val);
		accept(tok_number);
		break;
	case tok_int:
		val.set_int(int_val);
		accept(tok_int);
		break;
	case tok_bool:
		val.set_bool(bool_val);
		accept(tok_bool);
		break;
	case tok_nil:
		val.set_nil();
		accept(tok_nil);
		break;
	case tok_left_brace:
		if (accept(tok_left_brace))
		{
			json_object_t& obj=val.create_object();
			proc_object(obj);
			expect(tok_right_brace);
		}
		break;
	case tok_left_bracket:
		if (accept(tok_left_bracket))
		{
			json_array_t& arr=val.create_array();
			proc_array(arr);
			expect(tok_right_bracket);
		}
		break;

	default:
		val.set_num(0);
		error_string=_str("unexpected token %d [%d, %+d]",act_index+utf8_diff,act_index,utf8_diff);
		success=false;
	}

	return val;
}

void json_parser_t::proc_array(json_array_t& arr)
{
	arr.value_list.reserve(1000);
	if (act_token!=tok_right_bracket)
		while (1)
		{
			json_value_t val=proc_value();
			arr.value_list.push_back(val);

			if (act_token==tok_comma)
				accept(tok_comma);
			else
				break;
		}

		vector<json_value_t> tmp;
		tmp.resize(arr.value_list.size());
		for (unsigned n=0; n<tmp.size(); ++n)
		{
			tmp[n]=arr.value_list[n];
		}
		arr.value_list.swap(tmp);
}




bool sor_comment=false;
bool block_comment=false;

bool is_white_space(char c)
{
	if (c=='*' && !sor_comment)
		block_comment=!block_comment;
	if (c=='/')
		sor_comment=true;
	else if (c=='\n')
		sor_comment=false;
	return c==' ' || c=='\t' || c=='\n' || c=='\r' || sor_comment || c=='*' || block_comment;
}

bool is_number_prefix(const char c)
{
	return (c>='0' && c<='9') || c=='+' || c=='-';
}

bool is_number_character(const char c)
{
	return (c>='0' && c<='9') || c=='+' || c=='-'|| c=='.' || c=='e' || c=='E';
}

void json_parser_t::get_next_token()
{
	while (act_index<text_size && is_white_space(text[act_index]))
		++act_index;

	if (is_number_prefix(text[act_index]))
	{
		get_number();
	}
	else if (text[act_index]=='\"')
		get_string();
	else if (text[act_index]=='\'')
		get_hash();
	else if (text[act_index]=='[')
		get_left_bracket();
	else if (text[act_index]==']')
		get_right_bracket();
	else if (text[act_index]=='{')
		get_left_brace();
	else if (text[act_index]=='}')
		get_right_brace();
	else if (text[act_index]==',')
		get_comma();
	else if (text[act_index]==':')
		get_colon();
	else if (text[act_index]=='t')
		get_true_val();
	else if (text[act_index]=='f')
		get_false_val();
	else if (text[act_index]=='n')
		get_nil_val();
	else if (text[act_index]==0)
		get_eof();
	else
	{
		error_string=string(_str("unexpected token %d [%d: %+d] next 10 chars: ",act_index+utf8_diff,act_index,utf8_diff))+string(text+act_index,10);
		success=false;
	}
}

void json_parser_t::get_number()
{
	char tmp[128];
	int i=0;

	bool isfloat=false;
	while (is_number_character(text[act_index]))
	{
		if (!is_number_prefix(text[act_index]))
			isfloat=true;
		tmp[i++]=text[act_index++];
	}

	tmp[i]=0;

	if (isfloat)
	{
		float fp;
		int ret=sscanf(tmp,"%f",&fp);
		number_val=fp;
		act_token=tok_number;
	}
	else
	{
		int ip;
		int ret=sscanf(tmp,"%d",&ip);
		int_val=ip;
		act_token=tok_int;
	}

#ifdef NEED_ASSERT
	if (!ret)
	{
		char msg[128];
		sprintf (msg,"%s nem szam",tmp);
		ASSERTTXT(ret,msg);
	}
#endif

}

void json_parser_t::get_int()
{
	++act_index;
	char tmp[128];
	int i=0;

	while ((text[act_index]>='0' && text[act_index]<='9') || text[act_index]=='-')
		tmp[i++]=text[act_index++];

	tmp[i]=0;

	int ip;
	int ret=sscanf(tmp,"%d",&ip);
	int_val=ip;

	act_token=tok_int;
}

void json_parser_t::get_string()
{
	++act_index;

#if 0
	char *trg=str_val;
	char *term=str_val+JSON_STRING_BUFFER_SIZE-1;

	for (const char *s=text+act_index;*s && trg<term;++act_index)
	{
		if (*s=='\"')
		{
			++s;
			++act_index;

			if (*s!='\"')
				break;

			*trg++=*s++;
		}
		else if (*s=='\\')
		{
			++s;
			if (*s!='\"')
				*trg++='\\';
			else
			{
				++act_index;
				*trg++=*s++;
			}
		}
		else
			*trg++=*s++;
	}

	if (trg==term)
	{
		error_string="this->text_size>act_index";
		success=false;
		return;
	}

	*trg=0;

	utf8_diff+=calculate_utf8_length(str_val)-(trg-str_val);
#else
	int i=0;
	while (text[act_index]!='\"' || text[act_index+1]=='\"')
	{
		if (this->text_size<=act_index)
		{
			error_string="this->text_size>act_index";
			success=false;
			return;
		}
		if (text[act_index]=='\\' && text[act_index+1]=='\"')
		{
			++act_index;
		}
		if (text[act_index]=='\"' && text[act_index+1]=='\"')
		{
			++act_index;
		}
		ASSERT(i<JSON_STRING_BUFFER_SIZE);
		str_val[i++]=text[act_index++];
	}
	str_val[i]=0;
	++act_index;
#endif

	act_token=tok_str;
}

void json_parser_t::get_hash()
{
	++act_index;
	int i=0;


	while (text[act_index]!='\'')
	{
		if (this->text_size<=act_index)
		{
			error_string="this->text_size>act_index";
			success=false;
			return;
		}
/*
//hashben ne legyen mar idezojel
		if (text[act_index]=='\\' && text[act_index+1]=='\"')
		{
			++act_index;
		}
*/
		ASSERT(i<JSON_STRING_BUFFER_SIZE);
		str_val[i++]=text[act_index++];
	}
	str_val[i]=0;
	++act_index;
	hash_val.make(str_val);

	act_token=tok_hash;
}

void json_parser_t::get_comma()
{
	act_token=tok_comma;
	++act_index;
}

void json_parser_t::get_colon()
{
	act_token=tok_colon;
	++act_index;
}

void json_parser_t::get_left_bracket()
{
	act_token=tok_left_bracket;
	++act_index;
}

void json_parser_t::get_right_bracket()
{
	act_token=tok_right_bracket;
	++act_index;
}

void json_parser_t::get_left_brace()
{
	act_token=tok_left_brace;
	++act_index;
}

void json_parser_t::get_right_brace()
{
	act_token=tok_right_brace;
	++act_index;
}

void json_parser_t::get_nil_val()
{
	if (!strncmp(text+act_index,"null",4))
	{
		act_token=tok_nil;
		act_index+=4;
	}
	else
	{
		error_string="null value expected";
	}
}


void json_parser_t::get_false_val()
{
	if (!strncmp(text+act_index,"false",5))
	{
		act_token=tok_bool;
		bool_val=false;
		act_index+=5;
	}
	else
	{
		error_string="false value expected";
		success=false;
	}
}

void json_parser_t::get_true_val()
{
	if (!strncmp(text+act_index,"true",4))
	{
		act_token=tok_bool;
		bool_val=true;
		act_index+=4;
	}
	else
	{
		error_string="true value expected";
		success=false;
	}
}

void json_parser_t::get_eof()
{
	act_token=tok_eof;
}




#include "File/File.h"
json_object_t* generate_json_map(const char* filename)
{
	file_t file;
	if (!file.open(filename,"rb"))
		return NULL;

	char* buf=new char[file.length()+1];
	buf[file.length()]=0;
	file.read(buf,file.length());
	file.close();
	json_parser_t j;
	json_object_t* map=new json_object_t;
	j.process_text(buf,map);
	delete [] buf;

	if (!j.success)
	{
		ASSERTTXT(0,j.error_string.c_str());
		delete map;
		return 0;
	}
	return map;
}

json_object_t* generate_json_map_from_binary(const char* filename)
{
	file_t file;
	if (!file.open(filename,"rb"))
		return NULL;

	char* buf=new char[file.length()];
//	buf[file.length()]=0;
	file.read(buf,file.length());
	file.close();
	json_parser_t j;
	json_object_t* map=new json_object_t;
	j.process_binary(buf,map);
	delete [] buf;

	if (!j.success)
	{
		ASSERTTXT(0,j.error_string.c_str());
		delete map;
		return 0;
	}
	return map;
}
json_object_t* generate_json_map(const string& filestr)
{
	const char* buf=filestr.c_str();
	json_parser_t j;
	json_object_t* map=new json_object_t;
	j.process_text(buf,map);

	if (!j.success)
	{
		delete map;
		return 0;
	}
	return map;
}




#ifdef LEO_DESIGNER
string save_json_to_string(json_array_t* a);
string save_json_to_string(json_object_t* o,bool brace)
{
	string s;
	if (brace)
		s="\n{\n";
	for (unsigned int n=0; n<o->pair_list.size(); ++n)
	{
		s+="\""+string(o->pair_list[n].key.c_str())+"\": ";
		json_value_t& val=o->pair_list[n].val;

		switch (val.get_type())
		{
		case type_num:
			{
				char str[1024];
				sprintf(str,"%g",val.get_num());
				s+=string(str);
				break;
			}
		case type_int:
			{
				char str[1024];
				sprintf(str,"%d",val.get_int());
				s+=string(str);
				break;
			}
		case type_bool:
			{
				if (val.get_bool())
					s+="true";
				else
					s+="false";
				break;
			}
		case type_str:
			{
				s+="\"";
				s+=val.get_str();
				s+="\"";
				break;
			}
		case type_arr:
			{
				s+=save_json_to_string(&val.get_array());
				break;
			}
		case type_obj:
			{
				s+="\n"+save_json_to_string(&val.get_object());
				break;
			}
		default:
			ASSERT(0);
		}

		if (n<o->pair_list.size()-1)
			s+=",";

		s+="\n";
	}

	if (brace)
		s+="}";
	return s;
}

string save_json_to_string(json_array_t* a)
{
	string s;

	s="[";

	for (unsigned n=0; n<a->value_list.size(); ++n)
	{
		json_value_t& val=a->value_list[n];

		switch (val.get_type())
		{
		case type_num:
			{
				char str[1024];
				sprintf(str,"%g",val.get_num());
				s+=string(str);
				break;
			}
		case type_int:
			{
				char str[1024];
				sprintf(str,"%d",val.get_int());
				s+=string(str);
				break;
			}
		case type_bool:
			{
				if (val.get_bool())
					s+="true";
				else
					s+="false";
				break;
			}
		case type_str:
			{
				s+=val.get_str();
				break;
			}
		case type_arr:
			{
				s+=save_json_to_string(&val.get_array());
				break;
			}
		case type_obj:
			{
				s+="\n"+save_json_to_string(&val.get_object());
				break;
			}
		default:
			ASSERT(0);
		}

		if (n<a->value_list.size()-1)
			s+=",";
	}

	s+="]";


	return s;
}
#endif